#include <fhetext/RenderContext.h>
#include <fhe/math/Math.h>
#include <fhe/core/FileSystem.h>
#include <ncurses.h>

namespace fhe
{
  namespace text
  {
    RenderContext::RenderContext()
    {
    }
    
    RenderContext::~RenderContext()
    {
    }
    
    void RenderContext::putChar( const Vec2i& pos, char c )
    {
      back_[ transform() + pos ] = c;
    }
    
    void RenderContext::putString( const Vec2i& pos, const std::string& s, int align )
    {
      const int l = s.size();
      for ( int i = 0; i < l; ++i )
      {
        putChar( pos + Vec2i( l/2 * align - l/2 + i, 0 ), s[i] );
      }
    }
    
    void RenderContext::blit( const std::string& resource )
    {
      std::string text;
      if ( FileSystem::instance().hasFile( resource ) )
      {
        text = FileSystem::instance().readFile( resource );
      }
      else
      {
        text = resource;
      }
      const int halign = 1;
      const int valign = 1;
      const std::vector< std::string > lines = StringUtil::split( StringUtil::replace( text, "\\n", "\n" ), "\n" );
      const int l = lines.size();
      for ( int i = 0; i < l; ++i )
      {
        putString( Vec2i( 0, l/2 * valign - l/2 + i ), lines[i], halign );
      }
    }
    
    void RenderContext::renderChar( Vec2i pos, char c )
    {
      if ( pos.x >= 0 && pos.x < size_.x && pos.y >= 0 && pos.y < size_.y )
      {
        mvaddch( pos.y, pos.x, c );
      }
    }
    
    void RenderContext::render()
    {
      for ( Buffer::const_iterator i = back_.begin(); i != back_.end(); ++i )
      {
        Buffer::const_iterator j = front_.find( i->first );
        if ( j == front_.end() || i->second != j->second )
        {
          renderChar( i->first, i->second );
        }
      }
      for ( Buffer::const_iterator i = front_.begin(); i != front_.end(); ++i )
      {
        Buffer::const_iterator j = back_.find( i->first );
        if ( j == back_.end() )
        {
          renderChar( i->first, ' ' );
        }
      }
    }
    
    void RenderContext::swap()
    {
      front_ = back_;
      back_ = Buffer();
    }
    
    Vec2i RenderContext::size() const
    {
      return size_;
    }
    
    void RenderContext::setSize( const Vec2i& size )
    {
      size_ = size;
    }
    
    void RenderContext::translate( const Vec2i& pos )
    {
      transforms_.push_back( pos );
    }
    
    void RenderContext::rotate( const Rot2i& rot )
    {
      translate( Vec2i::ZERO );
    }
    
    void RenderContext::scale( const Vec2i& scale )
    {
      translate( Vec2i::ZERO );
    }
    
    Vec2i RenderContext::transform() const
    {
      Vec2i pos;
      for ( std::vector< Vec2i >::const_iterator i = transforms_.begin(); i != transforms_.end(); ++i )
      {
        pos += *i;
      }
      return pos;
    }
    
    void RenderContext::popTransform()
    {
      transforms_.pop_back();
    }
  }
}
